package com.yb.web.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;

import com.yb.framework.security.handler.AuthenticationFailureHandlerImpl;
import com.yb.framework.security.handler.AuthenticationSuccessHandlerImpl;

@Configuration
//使基于方法的授权生效
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private AuthenticationSuccessHandlerImpl successHandler;
	@Autowired
	private AuthenticationFailureHandlerImpl failureHandler;
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		// TODO Auto-generated method stub
		/**
		 * TOPJUI在进行编辑操作时，请求地址为不正规URL（带//）
		 * 解决不正规的URL请求被拦截的问题（"//api" -> "/api"）
		 * 参考：https://blog.csdn.net/kangkanglou/article/details/84568514
		 */
		web.httpFirewall(allowUrlEncodedDoubleSlash());
		
		/**
		 * 解决静态资源被拦截的问题
		 * web.ignoring()与http.permitAll()
		 * web.ignoring()是完全绕过了spring security的所有filter，相当于不走spring security；
		 * http.permitAll()没有绕过spring security，相当于只是允许该路径通过FilterChain。
		 */
		web.ignoring().antMatchers("/html/**", "/json/**", "/static/**", "/topjui/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// TODO Auto-generated method stub
		http.csrf().disable()
			.headers().frameOptions().disable()
			.and().authorizeRequests()
				.antMatchers("/login").anonymous()
				.antMatchers("/createValidateCodeImg").permitAll()
				.anyRequest().authenticated()
			.and().formLogin()
				.loginPage("/login")
				.loginProcessingUrl("/login")
				.successHandler(successHandler)
				.failureHandler(failureHandler)
			.and().logout()
				.logoutUrl("/logout")
				.logoutSuccessUrl("/login")
				.deleteCookies("JSESSIONID");
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// TODO Auto-generated method stub
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
	
	@Bean
	public PasswordEncoder passwordEncoder() {
		// 无加密
		// return NoOpPasswordEncoder.getInstance();
		// 强散列哈希加密
		return new BCryptPasswordEncoder();
	}
	
	@Bean
	public HttpFirewall allowUrlEncodedDoubleSlash() {
	    StrictHttpFirewall firewall = new StrictHttpFirewall();
	    // 允许请求URL中有“//”的请求通过
	    firewall.setAllowUrlEncodedDoubleSlash(true);
	    return firewall;
	}
	
	public static void main(String[] args) {
		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
		System.out.println(bCryptPasswordEncoder.encode("123456"));
	}
}
